#!/usr/local/bin/python
#-*- encoding=utf-8 -*-
import numpy as np
import scipy.sparse as sp
import time
import threading
import os
from multiprocessing import Process
from multiprocessing import Pool
import profile
import itertools
import ConfigParser
import numpy.matlib
from itertools import izip_longest

config = None;
def get_config():
    global config;
    if config == None:
        config = ConfigParser.SafeConfigParser();
        config.read('config');
    
    return config;
    

class COO_Struct:
    def __init__(self):
        self.data = [];
        self.row = [];
        self.col = [];

    def append(self, r, c, d):
        self.row.append(r);
        self.col.append(c);
        self.data.append(d);

def save_sparse_csc(filename, array):
    filename = 'Matrix/%s' % filename;
    if sp.isspmatrix_csc(array):
        np.savez(filename, format='csc', data=array.data, indices=array.indices, indptr=array.indptr, shape=array.shape);
    else:
        print '%s is not csc format' % array;

def load_sparse_csc(filename):
    filename = 'Matrix/%s' % filename;
    loader = np.load(filename);

    if loader['format'] == 'csc':
        return sp.csc_matrix((loader['data'], loader['indices'], loader['indptr']), shape=loader['shape']);
    else:
        print '%s is not csc format' % filename;

def save_sparse_csr(filename, array):
    filename = 'Matrix/%s' % filename;
    if sp.isspmatrix_csr(array):
        np.savez(filename, format='csr', data=array.data, indices=array.indices, indptr=array.indptr, shape=array.shape);
    else:
        print '%s is not csr format' % array;

def load_sparse_csr(filename):
    filename = 'Matrix/%s' % filename;
    loader = np.load(filename);
    if loader['format'] == 'csr':
        return sp.csr_matrix((loader['data'], loader['indices'], loader['indptr']), shape=loader['shape']);
    else:
        print '%s is not csr format' % filename;

def spellTrainSet(trainsetflag):
    if trainsetflag == 'five':
        return 'Train/train.set';
    elif trainsetflag == 'week':
        return 'Train/train.oneweek.set';
    else:
        return 'Train/train.onemonth.set';
def spellTestSet(testsetflag):
    if testsetflag == 'low':
        return 'TestSet/test.low.set';
    elif testsetflag == 'high':
        return 'TestSet/test.high.set';
    elif testsetflag == 'all':
        return 'TestSet/test.all.set';
    elif testsetflag == 'five':
        return 'TestSet/test.five.set';
    elif testsetflag == 'week':
        return 'TestSet/test.week.set';
    elif testsetflag == 'month':
        return 'TestSet/test.month.set';

def spellWNSet(trainsetflag):
    if trainsetflag == 'five':
        return 'W_Five.npz', 'N_Five.npz';
    elif trainsetflag == 'week':
        return 'W_Week.npz', 'N_Week.npz';
    else:
        return 'W_Month.npz', 'N_Month.npz';

def spellMeanSet(trainsetflag):
    if trainsetflag == 'five':
        return 'D_Five.Mean.npy', 'Q_Five.Mean.npy';
    elif trainsetflag == 'week':
        return 'D_Week.Mean.npy', 'Q_Week.Mean.npy';
    elif trainsetflag == 'month':
        return 'D_Month.Mean.npy', 'Q_Month.Mean.npy';

def spellModelName(modleflag, trainsetflag):
    return ('Lx_%s_%s.txt.npz' % (modleflag, trainsetflag), 'Ly_%s_%s.txt.npz' % (modleflag, trainsetflag));

def spellResultsName(modelflag, trainsetflag, testsetflag):
    return ('Results/%s_%s_%s.results' %(modelflag, trainsetflag, testsetflag), 'Results/bm25_%s.results' % (testsetflag,));

def spellSynName(s):
    if s == 'C':
        return 'context_I';
    elif s == 'P':
        return 'context_P';
    elif s == F:
        return 'context_F';


def sparseFroNorm2(W):
    s = 0.0;
    if sp.isspmatrix_lil(W):
        ch = itertools.chain(*W.data);
        l = map(float, ch);
    else:
        l = W.data;
    for d in l:
        s += d*d;
    return s;

def sparseFroNorm(W):
    s = 0.0;
    if sp.isspmatrix_lil(W):
        ch = itertools.chain(*W.data);
        l = map(float, ch);
    else:
        l = W.data;
    for d in l:
        s += d*d;
    return np.sqrt(s);

def grouper(n, iterable, padvalue=None):
    return izip_longest(*[iter(iterable)]*n, fillvalue=padvalue);

def normlize2(M, C):
    L = M.tolil();
    for i in range(M.shape[0]):
        print i;
        L[i] -= C;
    return L.tocsr();

def normlize(L, C):
    C = np.matlib.repmat(C, 1000, 1);
    print 'Here'
    for i in range(0, L.shape[0],1000):
        print i;
        #L[i] = M[i]  -C;
        if (i+1000 > L.shape[0]):
             interval =  L.shape[0] - i ;
        else:
            interval =  1000;
        L[i:i+interval]  = L[i:i+interval] - C[0:interval];
    return L;

def _computeWandN(start):
    print 'start', start;
    if start + interval > D.shape[0]:
        stop = D.shape[0];
    else:
        stop = start + interval;
    W = D[start:stop].transpose().dot(Q[start:stop]);
    #N = Q[start:stop].transpose().dot(D[start:stop]);

    print 'end', start;
    return (W, W);
#Compute W and N. D and Q are dense matrices, P is COO sparse matrix
global D, Q, interval;
def computeWandN(DD, QQ, K=25):
    global D, Q, interval;
    D = DD;
    Q = QQ;
    interval = D.shape[0] / K;
    pool = Pool(processes=K);
    li = range(0, D.shape[0], interval);
    results = pool.map(_computeWandN, li);
    W = np.matlib.empty(dy, dx);
    N = np.matlib.empty(dx, dy);
    for result in results:
        W += result[0];
        N += result[1];
    return (sp.csc_matrix(W),sp.csc_matrix(N));

#This is trick to compute (D-D_mean)^T(Q-Q_mean)
#D in CSR format, Q in CSC format
def computeWandN2(D, Q, D_mean, Q_mean, P):
    PQ = P.dot(Q);
    PD = P.dot(D);
    W1 = D.transpose().dot(PQ);
    print type(Q.sum(0)), Q.sum(0).shape
    W2 = W1 - D_mean.transpose().dot(PQ.sum(0));
    del(W1);
    W3 = W2 - PD.sum(0).transpose().dot(Q_mean);
    del(W2);
    W4 = W3 + D_mean.transpose().dot(Q_mean) * P.sum();
    del(W3);
    print type(W4), W4.max(), W4.min();
    return W4;

def _getColumnNorm(M, d):
       pass

def r2norm(M, d):
    arr = [];
    for i in range(d):
        row = M.getrow(i);
        n = sparseFroNorm(row);
        if n!=0:
            arr.append(1/float(n));
        else:
            arr.append(0);
    for i in range(d):
        M[i] = M[i] * arr[i];
 

def l2norm(M, d):
    arr = [];
    for i in range(d):
        col = M.getcol(i);
        n = sparseFroNorm(col);
        if n != 0:
            arr.append(1/float(n));
        else:
            arr.append(0);
    di = 0;
    for r, row in enumerate(M.rows):
        for c, ci in enumerate(row):
            #print r, c;
            M.data[r][c]*= arr[ci]
            di +=1
if __name__ == '__main__':
  
    Q = sp.rand(4, 4, density=0.5, format='lil');
    print Q.todense();
   
    l2norm(Q, 4);
    print Q.todense();
   
    print sparseFroNorm(Q);

